package com.xiaomaoguai.javassist.kepler.config;

import com.xiaomaoguai.fcp.pre.kepler.convert.core.ConvertTemplate;
import com.xiaomaoguai.javassist.kepler.dto.StandardBaseDTO;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.bytecode.SignatureAttribute;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * @author WeiHui
 * @version v1.0.0
 * @date 2019/4/20 12:27
 * @since JDK 1.8
 */
@Slf4j
@Configuration
public class HandlerClientAutoGenerator extends AbstractKeplerHandlerEnhancePostProcessor {

	/**
	 * bean 后缀
	 */
	public static final String CONVERT_CLIENT_SUFFIX = "ConvertClient";

	/**
	 * DCConvertClient 全限定名
	 */
	private static final String DC_CONVERT_CLIENT_NAME = DCConvertClient.class.getName();

	/**
	 * StandardBaseDTO 全限定名
	 */
	private static final String STANDARD_BASE_DTO_NAME = StandardBaseDTO.class.getName();

	/**
	 * 类池
	 */
	private static ClassPool pool;

	/**
	 * 初始化
	 */
	static {
		pool = ClassPool.getDefault();
		pool.insertClassPath(new ClassClassPath(HandlerClientAutoGenerator.class));
	}

	@Resource
	private ConvertTemplate convertTemplate;

	/**
	 * 后置处理-动态生成类-代理成bean
	 */
	@Override
	public void postProcessor() {
		//获取所有的Handler
		Map<String, Object> beans = getAllHandler();
		beans.forEach((k, v) -> {
			//得到目标类
			Class<?> targetClass = AopUtils.getTargetClass(v);
			String name = targetClass.getName();
			String simpleName = targetClass.getSimpleName();
			String convertClientName = name + CONVERT_CLIENT_SUFFIX;
			String convertClientSimpleName = simpleName + CONVERT_CLIENT_SUFFIX;

			//动态构建类信息
			CtClass ctClass = null;
			try {
				ctClass = pool.get(convertClientName);
			} catch (NotFoundException e) {
				log.debug(convertClientName + " not found, now create this!");
				try {
					//创建接口
					ctClass = pool.makeInterface(convertClientName);
					CtClass dcConvertClient = pool.get(DC_CONVERT_CLIENT_NAME);
					//获取handler的泛型参数
					final Type genericSuperclass = getParameterizedType(targetClass);
					String genericClassName;
					if (genericSuperclass != null) {
						genericClassName = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0].getTypeName();
					} else {
						genericClassName = STANDARD_BASE_DTO_NAME;
					}
					//添加泛型签名
					SignatureAttribute.ClassSignature cs = new SignatureAttribute.ClassSignature(new SignatureAttribute.TypeParameter[]{new SignatureAttribute.TypeParameter(genericClassName)});
					dcConvertClient.setGenericSignature(cs.encode());
					//继承DCConvertClient
					ctClass.addInterface(dcConvertClient);
					if (ctClass.isFrozen()) {
						ctClass.defrost();
					}
				} catch (NotFoundException ex) {
					log.error("create class " + convertClientName + " error", ex);
				}
			}
			if (ctClass != null) {
				registerConvertClientBean(convertClientSimpleName, ctClass);
			}
		});
	}

	/**
	 * 添加动态代理，注册Bean
	 *
	 * @param convertClientSimpleName beanName
	 * @param ctClass                 动态类
	 */
	private void registerConvertClientBean(String convertClientSimpleName, CtClass ctClass) {
		GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
		genericBeanDefinition.setBeanClass(HandlerConvertClientFactoryBean.class);
		genericBeanDefinition.getPropertyValues().add("serviceInterface", ctClass);
		genericBeanDefinition.getPropertyValues().add("convertTemplate", convertTemplate);
		genericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
		String beanName = StringUtils.uncapitalize(convertClientSimpleName);
		defaultListableBeanFactory.registerBeanDefinition(beanName, genericBeanDefinition);
		log.debug("新增handler格转Client:{}", beanName);
	}

}
